package com.cash.app.utils.extra.tools

import android.Manifest
import android.annotation.SuppressLint
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Point
import android.hardware.Sensor
import android.hardware.SensorManager
import android.media.AudioManager
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.net.Proxy
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.StatFs
import android.os.SystemClock
import android.provider.Settings
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import android.text.TextUtils
import android.text.format.Formatter
import android.util.DisplayMetrics
import android.util.Log
import android.view.KeyCharacterMap
import android.view.KeyEvent
import android.view.ViewConfiguration
import android.view.WindowManager
import androidx.core.app.ActivityCompat
import com.cash.app.utils.TLog
import com.cash.app.utils.extra.ExtraInfoUtils
import com.cash.app.utils.extra.model.SensorData
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
import java.io.IOException
import java.io.InputStreamReader
import java.net.NetworkInterface
import java.net.SocketException
import java.util.Locale
import kotlin.math.pow
import kotlin.math.sqrt

object OtherUtils {
    private val telephonyManager: TelephonyManager
        get() = ExtraInfoUtils.getApp()
            .getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager

    val baseband_Ver: String?
        /**
         * BASEBAND-VER
         * return String
         */
        get() {
            var Version = ""
            try {
                val cl = Class.forName("android.os.SystemProperties")
                val invoker = cl.newInstance()
                val m = cl.getMethod(
                    "get", *arrayOf<Class<*>>(
                        String::class.java, String::class.java
                    )
                )
                val result = m.invoke(
                    invoker, *arrayOf<Any>("gsm.version.baseband", "no message")
                )
                Version = result as String
            } catch (e: Exception) {
            }
            return Version
        }


    val resolutions: String
        get() {
            //获取真实屏幕宽高
            val outSize = Point()
            val wm: WindowManager =
                ExtraInfoUtils.getApp().getSystemService(Context.WINDOW_SERVICE) as WindowManager
            wm.getDefaultDisplay().getRealSize(outSize)
            val x = outSize.x
            val y = outSize.y
            return "$x*$y"
        }


    val serialNumbers: String?
        get() {
            var serial: String? = ""
            try {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { //10.0+
                    serial = GeneralUtils.gaid
                } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { //9.0+
                    serial = Build.SERIAL //  Build.getSerial();
                } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) { //8.0+
                    serial = Build.SERIAL
                } else { //8.0-
                    val c = Class.forName("android.os.SystemProperties")
                    val get = c.getMethod("get", String::class.java)
                    serial = get.invoke(c, "ro.serialno") as String
                }
            } catch (e: Exception) {
                e.printStackTrace()
                TLog.e("serialNumbers Exception：$e")
            }
            return serial
        }


    val screenSizeOfDevice2: String
        get() {
            val point = Point()
            val wm: WindowManager =
                ExtraInfoUtils.getApp().getSystemService(Context.WINDOW_SERVICE) as WindowManager
            wm.getDefaultDisplay().getRealSize(point)
            val dm: DisplayMetrics = ExtraInfoUtils.getApp().getResources().getDisplayMetrics()
            val x: Double = (point.x / dm.xdpi).toDouble().pow(2.0)
            val y: Double = (point.y / dm.ydpi).toDouble().pow(2.0)
            val screenInches = sqrt(x + y)
            return screenInches.toString()
        }


    @get:SuppressLint("MissingPermission")
    val judgeSIMCount: Int
        get() {
            if (ActivityCompat.checkSelfPermission(
                    ExtraInfoUtils.getApp(), Manifest.permission.READ_PHONE_STATE
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                return 0
            }
            var count = 0
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
                count = SubscriptionManager.from(ExtraInfoUtils.getApp())
                    .getActiveSubscriptionInfoCount()
                return count
            }
            return count
        }


    val phoneSimCount: Int
        get() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                return telephonyManager.getPhoneCount()
            }
            return 0
        }

    val isAppRoot: Int
        get() {
            var result = 0
            if (isDeviceRooted) {
                result = 1
            }
            return result
        }

    val isDeviceRooted: Boolean
        get() = checkRootMethod1() || checkRootMethod2() || checkRootMethod3()

    private fun checkRootMethod1(): Boolean {
        val buildTags = Build.TAGS
        return buildTags != null && buildTags.contains("test-keys")
    }

    private fun checkRootMethod2(): Boolean {
        val paths = arrayOf(
            "/system/app/Superuser.apk",
            "/sbin/su",
            "/system/bin/su",
            "/system/xbin/su",
            "/data/local/xbin/su",
            "/data/local/bin/su",
            "/system/sd/xbin/su",
            "/system/bin/failsafe/su",
            "/data/local/su",
            "/su/bin/su"
        )
        for (path in paths) {
            if (File(path).exists()) return true
        }
        return false
    }

    private fun checkRootMethod3(): Boolean {
        var process: Process? = null
        try {
            process = Runtime.getRuntime().exec(arrayOf("/system/xbin/which", "su"))
            val `in` = BufferedReader(InputStreamReader(process.inputStream))
            if (`in`.readLine() != null) return true
            return false
        } catch (t: Throwable) {
            return false
        } finally {
            process?.destroy()
        }
    }


    val isEmulator: Int
        get() {
            val checkProperty =
                Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.lowercase(Locale.getDefault())
                    .contains("vbox") || Build.FINGERPRINT.lowercase(Locale.getDefault())
                    .contains("test-keys") || Build.MODEL.contains("google_sdk") || Build.MODEL.contains(
                    "Emulator"
                ) || Build.MODEL.contains("Android SDK built for x86") || Build.MANUFACTURER.contains(
                    "Genymotion"
                ) || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith(
                    "generic"
                )) || "google_sdk" == Build.PRODUCT
            if (checkProperty) return 1
            var operatorName = ""
            val tm: TelephonyManager = ExtraInfoUtils.getApp()
                .getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            if (tm != null) {
                val name: String = tm.getNetworkOperatorName()
                if (name != null) {
                    operatorName = name
                }
            }
            val checkOperatorName = operatorName.lowercase(Locale.getDefault()) == "android"
            if (checkOperatorName) return 1

            val url = "tel:" + "123456"
            val intent = Intent()
            intent.setData(Uri.parse(url))
            intent.setAction(Intent.ACTION_DIAL)
            val checkDial =
                intent.resolveActivity(ExtraInfoUtils.getApp().getPackageManager()) == null
            if (checkDial) return 1
            return 0
        }

    val isMockLocation: Int
        get() {
            val isOpen = Settings.Secure.getInt(
                ExtraInfoUtils.getApp().getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 0
            ) != 0
            return if (isOpen) {
                1
            } else {
                0
            }
        }

    val isAppDebug: Int
        get() {
            val b = Settings.Secure.getInt(
                ExtraInfoUtils.getApp().getContentResolver(), Settings.Secure.ADB_ENABLED, 0
            ) > 0
            return if (b) {
                1
            } else {
                0
            }
        }

    val isAirplaneModeOn: Int
        get() {
            val b = Settings.Global.getInt(
                ExtraInfoUtils.getApp().getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0
            ) != 0
            return if (b) {
                1
            } else {
                0
            }
        }

    val phoneMode: Int
        get() {
            val audioManager: AudioManager =
                ExtraInfoUtils.getApp().getSystemService(Context.AUDIO_SERVICE) as AudioManager
            return audioManager.getRingerMode()
        }

    val proxyAddress: String
        get() {
            var port = ""
            if (checkVPN() == 1) {
                try {
                    val en = NetworkInterface.getNetworkInterfaces()
                    while (en.hasMoreElements()) {
                        val intf = en.nextElement()
                        val enumIpAddr = intf.inetAddresses
                        while (enumIpAddr.hasMoreElements()) {
                            val inetAddress = enumIpAddr.nextElement()
                            if (!inetAddress.isLoopbackAddress) {
                                if (intf.name.contains("tun")) {
                                    port = Formatter.formatIpAddress(inetAddress.hashCode())
                                }
                            }
                        }
                    }
                } catch (ex: SocketException) {
                    ex.printStackTrace()
                }
            }
            return port
        }

    val isWifiProxy: Int
        get() {
            val IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH
            val proxyAddress: String?
            val proxyPort: Int
            if (IS_ICS_OR_LATER) {
                proxyAddress = System.getProperty("http.proxyHost")
                val portStr = System.getProperty("http.proxyPort")
                proxyPort = (portStr ?: "-1").toInt()
            } else {
                proxyAddress = Proxy.getHost(ExtraInfoUtils.getApp())
                proxyPort = Proxy.getPort(ExtraInfoUtils.getApp())
            }
            val b = (!TextUtils.isEmpty(proxyAddress)) && (proxyPort != -1)
            return if (b) {
                1
            } else {
                0
            }
        }

    val hostAndPort: String
        get() {
            val IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH
            val proxyAddress: String?
            val proxyPort: Int
            if (IS_ICS_OR_LATER) {
                proxyAddress = System.getProperty("http.proxyHost")
                val portStr = System.getProperty("http.proxyPort")
                proxyPort = (portStr ?: "-1").toInt()
            } else {
                proxyAddress = Proxy.getHost(ExtraInfoUtils.getApp())
                proxyPort = Proxy.getPort(ExtraInfoUtils.getApp())
            }
            if (TextUtils.isEmpty(proxyAddress) && proxyPort == -1) {
                return ""
            }
            return "$proxyAddress:$proxyPort"
        }

    val bootTime: Long
        get() = System.currentTimeMillis() - SystemClock.elapsedRealtimeNanos() / 1000000


    @get:SuppressLint("NewApi")
    val mobileDbm: String
        get() {
            val dbm = ""
            //        TelephonyManager tm = getTelephonyManager();
//        if (ActivityCompat.checkSelfPermission(ExtraInfoUtils.getApp(), Manifest.permission.ACCESS_COARSE_LOCATION)
//                != PackageManager.PERMISSION_GRANTED) {
//            return dbm;
//        }
//        List<CellInfo> cellInfoList = tm.getAllCellInfo();
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
//            if (null != cellInfoList) {
//                for (CellInfo cellInfo : cellInfoList) {
//                    if (cellInfo instanceof CellInfoGsm) {
//                        CellSignalStrengthGsm cellSignalStrengthGsm = ((CellInfoGsm) cellInfo).getCellSignalStrength();
//                        dbm = String.valueOf(cellSignalStrengthGsm.getDbm());
//                    } else if (cellInfo instanceof CellInfoCdma) {
//                        CellSignalStrengthCdma cellSignalStrengthCdma = ((CellInfoCdma) cellInfo).getCellSignalStrength();
//                        dbm = String.valueOf(cellSignalStrengthCdma.getDbm());
//                    } else if (cellInfo instanceof CellInfoWcdma) {
//                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
//                            CellSignalStrengthWcdma cellSignalStrengthWcdma = ((CellInfoWcdma) cellInfo).getCellSignalStrength();
//                            dbm = String.valueOf(cellSignalStrengthWcdma.getDbm());
//                        }
//                    } else if (cellInfo instanceof CellInfoLte) {
//                        CellSignalStrengthLte cellSignalStrengthLte = ((CellInfoLte) cellInfo).getCellSignalStrength();
//                        dbm = String.valueOf(cellSignalStrengthLte.getDbm());
//                    }
//                }
//            }
//        }
            return dbm
        }

    val brightness: Int
        get() {
            val value = 255
            return Settings.System.getInt(
                ExtraInfoUtils.getApp().getContentResolver(),
                Settings.System.SCREEN_BRIGHTNESS,
                value
            )
        }


    val internalTotalSize: Long
        get() = getFsTotalSize(
            Environment.getDataDirectory().absolutePath
        )

    val internalAvailableSize: Long
        get() = getFsAvailableSize(
            Environment.getDataDirectory().absolutePath
        )

    val availMemory: Long
        get() {
            val am: ActivityManager = ExtraInfoUtils.getApp()
                .getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
            val mi: ActivityManager.MemoryInfo = ActivityManager.MemoryInfo()
            am.getMemoryInfo(mi)
            // mi.availMem; 当前系统的可用内存
            return mi.availMem
        }


    val totalMemory: Long
        get() {
            val str1 = "/proc/meminfo" // 系统内存信息文件
            val str2: String
            val arrayOfString: Array<String>
            var initial_memory: Long = 0
            try {
                val localFileReader = FileReader(str1)
                val localBufferedReader = BufferedReader(localFileReader, 8192)
                str2 = localBufferedReader.readLine()
                arrayOfString =
                    str2.split("\\s+".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                for (num in arrayOfString) {
                    Log.i(str2, num + "\t")
                }
                val i = arrayOfString[1].toInt()
                //int值乘以1024转换为long类型
                initial_memory = i.toLong() * 1024
                localBufferedReader.close()
            } catch (e: IOException) {
            }
            return initial_memory
        }


    fun getFsTotalSize(anyPathInFs: String?): Long {
        if (TextUtils.isEmpty(anyPathInFs)) return 0
        val statFs: StatFs = StatFs(anyPathInFs)
        val blockSize: Long
        val totalSize: Long
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            blockSize = statFs.getBlockSizeLong()
            totalSize = statFs.getBlockCountLong()
        } else {
            blockSize = statFs.getBlockSize().toLong()
            totalSize = statFs.getBlockCount().toLong()
        }
        return blockSize * totalSize
    }

    fun getFsAvailableSize(anyPathInFs: String?): Long {
        if (TextUtils.isEmpty(anyPathInFs)) return 0
        val statFs: StatFs = StatFs(anyPathInFs)
        val blockSize: Long
        val availableSize: Long
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            blockSize = statFs.getBlockSizeLong()
            availableSize = statFs.getAvailableBlocksLong()
        } else {
            blockSize = statFs.getBlockSize().toLong()
            availableSize = statFs.getAvailableBlocks().toLong()
        }
        return blockSize * availableSize
    }


    val screenDensity: Float
        get() = Resources.getSystem().displayMetrics.density

    val screenDensityDpi: Int
        get() = Resources.getSystem().displayMetrics.densityDpi

    val isTabletDevice: Int
        get() {
            val b: Boolean =
                (ExtraInfoUtils.getApp().resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE
            return if (b) {
                1
            } else {
                0
            }
        }


    fun getSensorList(sensorData: SensorData): SensorData {
        val sensorManager: SensorManager =
            ExtraInfoUtils.getApp().getSystemService(Context.SENSOR_SERVICE) as SensorManager
        val sensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)
        for (item in sensors) {
            val storageDatas: SensorData.SensorInfo = SensorData.SensorInfo()
            storageDatas.type = item.type
            storageDatas.name = item.name
            storageDatas.version = item.version
            storageDatas.vendor = item.vendor
            storageDatas.max_range = item.maximumRange
            storageDatas.min_delay = item.minDelay
            storageDatas.power = item.power
            storageDatas.resolution = item.resolution
            sensorData.sensor_lists.add(storageDatas)
        }
        return sensorData
    }


    fun checkDeviceHasNavigationBar(): Int {
        val hasMenuKey = ViewConfiguration.get(ExtraInfoUtils.getApp()).hasPermanentMenuKey()
        val hasBackKey: Boolean = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK)
        if (!hasMenuKey && !hasBackKey) {
            return 0
        }
        return 1
    }


    fun checkVPN(): Int {
        val cm: ConnectivityManager = ExtraInfoUtils.getApp()
            .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val networkInfo: NetworkInfo? = cm.getNetworkInfo(ConnectivityManager.TYPE_VPN)
        if (networkInfo != null) {
            return if (networkInfo.isConnectedOrConnecting()) 1 else 0
        }
        return 0
    }


    val isNetState: Int
        get() {
            val connectivityManager: ConnectivityManager = ExtraInfoUtils.getApp()
                .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val activeNetworkInfo: NetworkInfo =
                connectivityManager.getActiveNetworkInfo() ?: return 0
            val type: Int = activeNetworkInfo.getType()
            return when (type) {
                ConnectivityManager.TYPE_WIFI -> 1
                ConnectivityManager.TYPE_MOBILE -> 2
                else -> 0
            }
        }
}
